<?php

require_once('frontstart.inc.php');   # defines: $options[], $context
require 'ExtDirect.php';

global $options, $debug_sql, $trace, $neat;
if (isset($options) && isset($options['test_mode']) && $options['test_mode']) {
    if ($_SERVER['REQUEST_METHOD'] == 'GET') {
        if (isset($_REQUEST['debug_sql'])) $debug_sql = $_REQUEST['debug_sql'];
        if (isset($_REQUEST['trace']))     $trace     = $_REQUEST['trace'];
        if (isset($_REQUEST['neat']))      $neat      = $_REQUEST['neat'];
    }
}

class Database {
    # ------------------------------------------------------------------------
    # -- Public Functions for Ext Direct
    # ------------------------------------------------------------------------

    public function listDatabaseObjects ($db_name=null, $table_name=null) {
        global $trace, $context;
        if ($trace) trace_entry();

        $authdb = $context->authdb();
        $results = array('success' => true);

        # get all databases we are authorized to see
        $get_options = array('raw'=>1);
        $results['databases'] = $context->get_database_defs();

        $count     = count($results['databases']);
        $db_id     = null;
        $schema_id = null;
        # if a specific database was identified as being current...
        if (isset($db_name)) {
            # look for it in the list of authorized databases
            for ($i = 0; $i < $count; $i++) {
                if ($db_name === $results['databases'][$i]['db_name']) {
                    $db_id     = $results['databases'][$i]['db_id'];
                    $results['currentDatabaseName'] = $db_name;
                    $results['currentDatabaseId']   = $db_id;
                    break;
                }
            }
            # if we didn't find it, unset the current name
            if (!isset($db_id)) {
                $db_name = null;
            }
        }
        # if we still don't know an identified, authorized database...
        if (!isset($db_name)) {
            # choose the first database in the list
            if ($count > 0) {
                $db_id   = $results['databases'][0]['db_id'];
                $db_name = $results['databases'][0]['db_name'];
                $results['currentDatabaseName'] = $db_name;
                $results['currentDatabaseId']   = $db_id;
            }
            # or admit there are none
            else {
                $results['currentDatabaseName'] = null;
                $results['currentDatabaseId']   = null;
                $db_id   = null;
                $db_name = null;
            }
        }
       
        # TODO: remove this when we get the automated metadata stuff working right
        if (isset($db_id)) {
            $db = $context->database($db_name);
            $schema_names = $db->get_schema_names();   # initialize metadata if necessary
            if (count($schema_names) == 0) $db->init_table_defs();
        }

        if (isset($db_id)) {
            # get all tables we are authorized to see for the selected database
            $table_names       = $db->get_table_names();   # initialize the metadata if necessary
            $table_defs_by_table_name = $db->get_table_defs();
            $table_defs = array();
            foreach ($table_defs_by_table_name as $table_def) {
                $table_defs[] = $table_def;
            }
            $results['tables'] = $table_defs;

            $count = count($results['tables']);
            $table_id = null;
            # if a specific table was identified as being current...
            if (isset($table_name)) {
                # look for it in the list of authorized tables
                for ($i = 0; $i < $count; $i++) {
                    if ($table_name === $results['tables'][$i]['table_name']) {
                        $table_id     = $results['tables'][$i]['table_id'];
                        $results['currentTableName'] = $table_name;
                        $results['currentTableId']   = $table_id;
                        break;
                    }
                }
                # if we didn't find it, unset the current name
                if (!isset($table_id)) {
                    $table_name = null;
                }
            }
            # if we still don't know an identified, authorized table...
            if (!isset($table_name)) {
                # choose the first table in the list
                if ($count > 0) {
                    $table_id   = $results['tables'][0]['table_id'];
                    $table_name = $results['tables'][0]['table_name'];
                    $results['currentTableName'] = $table_name;
                    $results['currentTableId']   = $table_id;
                }
                # or admit there are none
                else {
                    $results['currentTableName'] = null;
                    $results['currentTableId']   = null;
                }
            }
        }
        else {
            $results['tables'] = array();
            $results['currentTableName'] = null;
            $results['currentTableId']   = null;
        }

        if (isset($table_id)) {
            $table_def = $db->get_table_def($table_name);
            # get all columns we are authorized to see for the selected table
            $results['columns'] = $table_def['columns'];
        }
        else {
            $results['columns'] = array();
        }

        if ($trace) trace_exit($results);
        return($results);
    }

    public function createDatabase ($dbValues) {
        global $trace;
        if ($trace) trace_entry();
        if (is_object($dbValues)) $dbValues = $this->_objectToAssoc($dbValues);
        $dbValues['create'] = true;
        $results = $this->_createDatabase($dbValues);
        if ($trace) trace_exit($results);
        return($results);
    }

    public function createDatabaseTable ($dbValues) {
        global $trace;
        if ($trace) trace_entry();
        if (is_object($dbValues)) $dbValues = $this->_objectToAssoc($dbValues);
        $results = $this->_createDatabaseTable($dbValues);
        if ($trace) trace_exit($results);
        return($results);
    }

    public function refreshDatabaseInformation ($db_name, $schema_name=null, $table_name=null) {
        global $trace;
        if ($trace) trace_entry();
        try {
            $db = $context->database($db_name);
            $db->init_table_defs($schema_name, $table_name);
            $results['success'] = true;
        }
        catch (Exception $e) {
            $results['success'] = false;
            $msg = strtolower($e->getMessage());
            $db_spec = $db_name . '.' .
                       (isset($schema_name) ? $schema_name : '*') .  '.' .
                       (isset($table_name) ? $table_name : '*');
            $results['message'] = "Error refreshing database ($db_spec): " . $msg;
        }
        if ($trace) trace_exit($results);
        return($results);
    }

    # ------------------------------------------------------------------------

    private function _createDatabase ($dbValues) {
        global $trace, $context;
        if ($trace) trace_entry();
        $results = array();
        try {
            $this->_supplementDbValues($dbValues);
            $db = $context->database($dbValues['db_name'], $dbValues);
            $db->init_table_defs();
            $results['success'] = true;
        }
        catch (Exception $e) {
            $results['success'] = false;
            $msg = strtolower($e->getMessage());
            if (strpos($msg,'unique') === false) {
                $results['message'] = "Error creating database ($dbValues[db_name]): " . $msg;
            }
            else {
                $results['sysmessage'] = $msg;
                $results['message']    = "Error creating database ($dbValues[db_name]): Database already exists";
            }
        }
        if ($trace) trace_exit($results);
        return($results);
    }

    private function _createDatabaseTable ($dbValues) {
        global $trace, $context;
        if ($trace) trace_entry();
        $results = array();
        try {
            $db = $context->database($dbValues['db_name']);
            $table_def = $this->_formValuesToTableDef($dbValues);
            $db->create_table($dbValues['schema_name'].'.'.$dbValues['table_name'], $table_def);
            $results['success'] = true;
        }
        catch (Exception $e) {
            $results['success'] = false;
            $msg = strtolower($e->getMessage());
            $results['message'] = "Error creating database table ($dbValues[table_name]): " . $msg;
        }
        if ($trace) trace_exit($results);
        return($results);
    }

    private function _formValuesToTableDef ($dbValues) {
        global $trace, $context;
        if ($trace) trace_entry();
        $table_def = array();

        if ($trace) trace_exit($table_def);
        return($table_def);
    }

    private function _supplementDbValues (&$dbValues) {
        global $trace, $context;
        if ($trace) trace_entry();
        $group_id = $context->getAuthenticatedGroupId();

        # dbtype => db_class
        if ($dbValues['dbtype'] === 'mysql') {
            $dbValues['db_class'] = 'App\\MySQLDatabase';
        }
        elseif ($dbValues['dbtype'] === 'oracle') {
            $dbValues['db_class'] = 'App\\OracleDatabase';
        }
        else {
            $dbValues['dbtype']   = 'sqlite';
            $dbValues['db_class'] = 'App\\SqlitePDODatabase';
            if (!isset($dbValues['dbschema'])) $dbValues['dbschema'] = 'main';
        }

        # db_name => db_label
        if ((!isset($dbValues['db_label']) || $dbValues['db_label'] === '') && isset($dbValues['db_name']))
                   $dbValues['db_label'] = $dbValues['db_name'];

        # db_label => db_desc
        if ((!isset($dbValues['db_desc']) || $dbValues['db_desc'] === '') && isset($dbValues['db_label']))
                   $dbValues['db_desc'] = $dbValues['db_label'];

        # dbname => dbdsn
        if ($dbValues['dbtype'] == 'sqlite') {
            if (!isset($dbValues['dbdsn']) && isset($dbValues['dbname']))
                       $dbValues['dbdsn'] = 'sqlite:' . $context->getOwnerDir('/db') . '/' . $dbValues['dbname'] . '.sq3';
        }

        if ($trace) trace_exit($dbValues);
    }

    private function _objectToAssoc ($obj) {
        global $trace;
        if ($trace) trace_entry();
        $array = array();
        foreach ($obj as $key => $value) {
            $array[$key] = $value;
        }
        if ($trace) trace_exit($array);
        return($array);
    }

    # used for debugging
    public function __toString() {
        return('[Database]');
    }
}

try {
    ExtDirect::provide('Database');
}
catch (Exception $e) {
    echo $e->getMessage();
}

